{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "visualization_of_the_filters_of_VGG16.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "authorship_tag": "ABX9TyPTAdXlIvUK7kKV1j8KyKuw",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/SummerLife/EmbeddedSystem/blob/master/MachineLearning/gist/visualization_of_the_filters_of_VGG16.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "F40Qv42HOINP",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        },
        "outputId": "8ddee067-bd4f-456b-df1c-21ee42990b63"
      },
      "source": [
        "\"\"\"\n",
        "#Visualization of the filters of VGG16, via gradient ascent in input space.\n",
        "\n",
        "This script can run on CPU in a few minutes.\n",
        "\n",
        "Results example: ![Visualization](http://i.imgur.com/4nj4KjN.jpg)\n",
        "\"\"\"\n",
        "from __future__ import print_function\n",
        "\n",
        "import time\n",
        "import numpy as np\n",
        "from PIL import Image as pil_image\n",
        "from keras.preprocessing.image import save_img\n",
        "from keras import layers\n",
        "from keras.applications import vgg16\n",
        "from keras import backend as K\n",
        "\n",
        "\n",
        "def normalize(x):\n",
        "    \"\"\"utility function to normalize a tensor.\n",
        "\n",
        "    # Arguments\n",
        "        x: An input tensor.\n",
        "\n",
        "    # Returns\n",
        "        The normalized input tensor.\n",
        "    \"\"\"\n",
        "    return x / (K.sqrt(K.mean(K.square(x))) + K.epsilon())\n",
        "\n",
        "\n",
        "def deprocess_image(x):\n",
        "    \"\"\"utility function to convert a float array into a valid uint8 image.\n",
        "\n",
        "    # Arguments\n",
        "        x: A numpy-array representing the generated image.\n",
        "\n",
        "    # Returns\n",
        "        A processed numpy-array, which could be used in e.g. imshow.\n",
        "    \"\"\"\n",
        "    # normalize tensor: center on 0., ensure std is 0.25\n",
        "    x -= x.mean()\n",
        "    x /= (x.std() + K.epsilon())\n",
        "    x *= 0.25\n",
        "\n",
        "    # clip to [0, 1]\n",
        "    x += 0.5\n",
        "    x = np.clip(x, 0, 1)\n",
        "\n",
        "    # convert to RGB array\n",
        "    x *= 255\n",
        "    if K.image_data_format() == 'channels_first':\n",
        "        x = x.transpose((1, 2, 0))\n",
        "    x = np.clip(x, 0, 255).astype('uint8')\n",
        "    return x\n",
        "\n",
        "\n",
        "def process_image(x, former):\n",
        "    \"\"\"utility function to convert a valid uint8 image back into a float array.\n",
        "       Reverses `deprocess_image`.\n",
        "\n",
        "    # Arguments\n",
        "        x: A numpy-array, which could be used in e.g. imshow.\n",
        "        former: The former numpy-array.\n",
        "                Need to determine the former mean and variance.\n",
        "\n",
        "    # Returns\n",
        "        A processed numpy-array representing the generated image.\n",
        "    \"\"\"\n",
        "    if K.image_data_format() == 'channels_first':\n",
        "        x = x.transpose((2, 0, 1))\n",
        "    return (x / 255 - 0.5) * 4 * former.std() + former.mean()\n",
        "\n",
        "\n",
        "def visualize_layer(model,\n",
        "                    layer_name,\n",
        "                    step=1.,\n",
        "                    epochs=15,\n",
        "                    upscaling_steps=9,\n",
        "                    upscaling_factor=1.2,\n",
        "                    output_dim=(412, 412),\n",
        "                    filter_range=(0, None)):\n",
        "    \"\"\"Visualizes the most relevant filters of one conv-layer in a certain model.\n",
        "\n",
        "    # Arguments\n",
        "        model: The model containing layer_name.\n",
        "        layer_name: The name of the layer to be visualized.\n",
        "                    Has to be a part of model.\n",
        "        step: step size for gradient ascent.\n",
        "        epochs: Number of iterations for gradient ascent.\n",
        "        upscaling_steps: Number of upscaling steps.\n",
        "                         Starting image is in this case (80, 80).\n",
        "        upscaling_factor: Factor to which to slowly upgrade\n",
        "                          the image towards output_dim.\n",
        "        output_dim: [img_width, img_height] The output image dimensions.\n",
        "        filter_range: Tupel[lower, upper]\n",
        "                      Determines the to be computed filter numbers.\n",
        "                      If the second value is `None`,\n",
        "                      the last filter will be inferred as the upper boundary.\n",
        "    \"\"\"\n",
        "\n",
        "    def _generate_filter_image(input_img,\n",
        "                               layer_output,\n",
        "                               filter_index):\n",
        "        \"\"\"Generates image for one particular filter.\n",
        "\n",
        "        # Arguments\n",
        "            input_img: The input-image Tensor.\n",
        "            layer_output: The output-image Tensor.\n",
        "            filter_index: The to be processed filter number.\n",
        "                          Assumed to be valid.\n",
        "\n",
        "        #Returns\n",
        "            Either None if no image could be generated.\n",
        "            or a tuple of the image (array) itself and the last loss.\n",
        "        \"\"\"\n",
        "        s_time = time.time()\n",
        "\n",
        "        # we build a loss function that maximizes the activation\n",
        "        # of the nth filter of the layer considered\n",
        "        if K.image_data_format() == 'channels_first':\n",
        "            loss = K.mean(layer_output[:, filter_index, :, :])\n",
        "        else:\n",
        "            loss = K.mean(layer_output[:, :, :, filter_index])\n",
        "\n",
        "        # we compute the gradient of the input picture wrt this loss\n",
        "        grads = K.gradients(loss, input_img)[0]\n",
        "\n",
        "        # normalization trick: we normalize the gradient\n",
        "        grads = normalize(grads)\n",
        "\n",
        "        # this function returns the loss and grads given the input picture\n",
        "        iterate = K.function([input_img], [loss, grads])\n",
        "\n",
        "        # we start from a gray image with some random noise\n",
        "        intermediate_dim = tuple(\n",
        "            int(x / (upscaling_factor ** upscaling_steps)) for x in output_dim)\n",
        "        if K.image_data_format() == 'channels_first':\n",
        "            input_img_data = np.random.random(\n",
        "                (1, 3, intermediate_dim[0], intermediate_dim[1]))\n",
        "        else:\n",
        "            input_img_data = np.random.random(\n",
        "                (1, intermediate_dim[0], intermediate_dim[1], 3))\n",
        "        input_img_data = (input_img_data - 0.5) * 20 + 128\n",
        "\n",
        "        # Slowly upscaling towards the original size prevents\n",
        "        # a dominating high-frequency of the to visualized structure\n",
        "        # as it would occur if we directly compute the 412d-image.\n",
        "        # Behaves as a better starting point for each following dimension\n",
        "        # and therefore avoids poor local minima\n",
        "        for up in reversed(range(upscaling_steps)):\n",
        "            # we run gradient ascent for e.g. 20 steps\n",
        "            for _ in range(epochs):\n",
        "                loss_value, grads_value = iterate([input_img_data])\n",
        "                input_img_data += grads_value * step\n",
        "\n",
        "                # some filters get stuck to 0, we can skip them\n",
        "                if loss_value <= K.epsilon():\n",
        "                    return None\n",
        "\n",
        "            # Calculate upscaled dimension\n",
        "            intermediate_dim = tuple(\n",
        "                int(x / (upscaling_factor ** up)) for x in output_dim)\n",
        "            # Upscale\n",
        "            img = deprocess_image(input_img_data[0])\n",
        "            img = np.array(pil_image.fromarray(img).resize(intermediate_dim,\n",
        "                                                           pil_image.BICUBIC))\n",
        "            input_img_data = np.expand_dims(\n",
        "                process_image(img, input_img_data[0]), 0)\n",
        "\n",
        "        # decode the resulting input image\n",
        "        img = deprocess_image(input_img_data[0])\n",
        "        e_time = time.time()\n",
        "        print('Costs of filter {:3}: {:5.0f} ( {:4.2f}s )'.format(filter_index,\n",
        "                                                                  loss_value,\n",
        "                                                                  e_time - s_time))\n",
        "        return img, loss_value\n",
        "\n",
        "    def _draw_filters(filters, n=None):\n",
        "        \"\"\"Draw the best filters in a nxn grid.\n",
        "\n",
        "        # Arguments\n",
        "            filters: A List of generated images and their corresponding losses\n",
        "                     for each processed filter.\n",
        "            n: dimension of the grid.\n",
        "               If none, the largest possible square will be used\n",
        "        \"\"\"\n",
        "        if n is None:\n",
        "            n = int(np.floor(np.sqrt(len(filters))))\n",
        "\n",
        "        # the filters that have the highest loss are assumed to be better-looking.\n",
        "        # we will only keep the top n*n filters.\n",
        "        filters.sort(key=lambda x: x[1], reverse=True)\n",
        "        filters = filters[:n * n]\n",
        "\n",
        "        # build a black picture with enough space for\n",
        "        # e.g. our 8 x 8 filters of size 412 x 412, with a 5px margin in between\n",
        "        MARGIN = 5\n",
        "        width = n * output_dim[0] + (n - 1) * MARGIN\n",
        "        height = n * output_dim[1] + (n - 1) * MARGIN\n",
        "        stitched_filters = np.zeros((width, height, 3), dtype='uint8')\n",
        "\n",
        "        # fill the picture with our saved filters\n",
        "        for i in range(n):\n",
        "            for j in range(n):\n",
        "                img, _ = filters[i * n + j]\n",
        "                width_margin = (output_dim[0] + MARGIN) * i\n",
        "                height_margin = (output_dim[1] + MARGIN) * j\n",
        "                stitched_filters[\n",
        "                    width_margin: width_margin + output_dim[0],\n",
        "                    height_margin: height_margin + output_dim[1], :] = img\n",
        "\n",
        "        # save the result to disk\n",
        "        save_img('vgg_{0:}_{1:}x{1:}.png'.format(layer_name, n), stitched_filters)\n",
        "\n",
        "    # this is the placeholder for the input images\n",
        "    assert len(model.inputs) == 1\n",
        "    input_img = model.inputs[0]\n",
        "\n",
        "    # get the symbolic outputs of each \"key\" layer (we gave them unique names).\n",
        "    layer_dict = dict([(layer.name, layer) for layer in model.layers[1:]])\n",
        "\n",
        "    output_layer = layer_dict[layer_name]\n",
        "    assert isinstance(output_layer, layers.Conv2D)\n",
        "\n",
        "    # Compute to be processed filter range\n",
        "    filter_lower = filter_range[0]\n",
        "    filter_upper = (filter_range[1]\n",
        "                    if filter_range[1] is not None\n",
        "                    else len(output_layer.get_weights()[1]))\n",
        "    assert(filter_lower >= 0\n",
        "           and filter_upper <= len(output_layer.get_weights()[1])\n",
        "           and filter_upper > filter_lower)\n",
        "    print('Compute filters {:} to {:}'.format(filter_lower, filter_upper))\n",
        "\n",
        "    # iterate through each filter and generate its corresponding image\n",
        "    processed_filters = []\n",
        "    for f in range(filter_lower, filter_upper):\n",
        "        img_loss = _generate_filter_image(input_img, output_layer.output, f)\n",
        "\n",
        "        if img_loss is not None:\n",
        "            processed_filters.append(img_loss)\n",
        "\n",
        "    print('{} filter processed.'.format(len(processed_filters)))\n",
        "    # Finally draw and store the best filters to disk\n",
        "    _draw_filters(processed_filters)\n",
        "\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    # the name of the layer we want to visualize\n",
        "    # (see model definition at keras/applications/vgg16.py)\n",
        "    LAYER_NAME = 'block5_conv1'\n",
        "\n",
        "    # build the VGG16 network with ImageNet weights\n",
        "    vgg = vgg16.VGG16(weights='imagenet', include_top=False)\n",
        "    print('Model loaded.')\n",
        "    vgg.summary()\n",
        "\n",
        "    # example function call\n",
        "    # visualize_layer(vgg, LAYER_NAME)\n",
        "\n",
        "    visualize_layer(vgg, \"block1_conv1\")\n",
        "    visualize_layer(vgg, \"block2_conv1\")\n",
        "\n"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Model loaded.\n",
            "Model: \"vgg16\"\n",
            "_________________________________________________________________\n",
            "Layer (type)                 Output Shape              Param #   \n",
            "=================================================================\n",
            "input_3 (InputLayer)         (None, None, None, 3)     0         \n",
            "_________________________________________________________________\n",
            "block1_conv1 (Conv2D)        (None, None, None, 64)    1792      \n",
            "_________________________________________________________________\n",
            "block1_conv2 (Conv2D)        (None, None, None, 64)    36928     \n",
            "_________________________________________________________________\n",
            "block1_pool (MaxPooling2D)   (None, None, None, 64)    0         \n",
            "_________________________________________________________________\n",
            "block2_conv1 (Conv2D)        (None, None, None, 128)   73856     \n",
            "_________________________________________________________________\n",
            "block2_conv2 (Conv2D)        (None, None, None, 128)   147584    \n",
            "_________________________________________________________________\n",
            "block2_pool (MaxPooling2D)   (None, None, None, 128)   0         \n",
            "_________________________________________________________________\n",
            "block3_conv1 (Conv2D)        (None, None, None, 256)   295168    \n",
            "_________________________________________________________________\n",
            "block3_conv2 (Conv2D)        (None, None, None, 256)   590080    \n",
            "_________________________________________________________________\n",
            "block3_conv3 (Conv2D)        (None, None, None, 256)   590080    \n",
            "_________________________________________________________________\n",
            "block3_pool (MaxPooling2D)   (None, None, None, 256)   0         \n",
            "_________________________________________________________________\n",
            "block4_conv1 (Conv2D)        (None, None, None, 512)   1180160   \n",
            "_________________________________________________________________\n",
            "block4_conv2 (Conv2D)        (None, None, None, 512)   2359808   \n",
            "_________________________________________________________________\n",
            "block4_conv3 (Conv2D)        (None, None, None, 512)   2359808   \n",
            "_________________________________________________________________\n",
            "block4_pool (MaxPooling2D)   (None, None, None, 512)   0         \n",
            "_________________________________________________________________\n",
            "block5_conv1 (Conv2D)        (None, None, None, 512)   2359808   \n",
            "_________________________________________________________________\n",
            "block5_conv2 (Conv2D)        (None, None, None, 512)   2359808   \n",
            "_________________________________________________________________\n",
            "block5_conv3 (Conv2D)        (None, None, None, 512)   2359808   \n",
            "_________________________________________________________________\n",
            "block5_pool (MaxPooling2D)   (None, None, None, 512)   0         \n",
            "=================================================================\n",
            "Total params: 14,714,688\n",
            "Trainable params: 14,714,688\n",
            "Non-trainable params: 0\n",
            "_________________________________________________________________\n",
            "Compute filters 0 to 64\n",
            "Costs of filter   0:    26 ( 0.54s )\n",
            "Costs of filter   1:    51 ( 0.55s )\n",
            "Costs of filter   2:    11 ( 0.54s )\n",
            "Costs of filter   3:    24 ( 0.56s )\n",
            "Costs of filter   4:    14 ( 0.59s )\n",
            "Costs of filter   6:    14 ( 0.58s )\n",
            "Costs of filter   7:    15 ( 0.60s )\n",
            "Costs of filter   8:    81 ( 0.60s )\n",
            "Costs of filter   9:    33 ( 0.61s )\n",
            "Costs of filter  10:    30 ( 0.61s )\n",
            "Costs of filter  11:    26 ( 0.56s )\n",
            "Costs of filter  12:    93 ( 0.59s )\n",
            "Costs of filter  13:    32 ( 0.55s )\n",
            "Costs of filter  14:    21 ( 0.55s )\n",
            "Costs of filter  15:    60 ( 0.54s )\n",
            "Costs of filter  16:    52 ( 0.55s )\n",
            "Costs of filter  17:    14 ( 0.55s )\n",
            "Costs of filter  18:    66 ( 0.55s )\n",
            "Costs of filter  20:    32 ( 0.56s )\n",
            "Costs of filter  21:    19 ( 0.56s )\n",
            "Costs of filter  22:    51 ( 0.57s )\n",
            "Costs of filter  23:    39 ( 0.55s )\n",
            "Costs of filter  24:    21 ( 0.57s )\n",
            "Costs of filter  25:    54 ( 0.58s )\n",
            "Costs of filter  26:    24 ( 0.58s )\n",
            "Costs of filter  27:    52 ( 0.59s )\n",
            "Costs of filter  28:    19 ( 0.59s )\n",
            "Costs of filter  29:    54 ( 0.60s )\n",
            "Costs of filter  30:    14 ( 0.60s )\n",
            "Costs of filter  31:    45 ( 0.63s )\n",
            "Costs of filter  33:    29 ( 0.61s )\n",
            "Costs of filter  34:    21 ( 0.62s )\n",
            "Costs of filter  35:    22 ( 0.63s )\n",
            "Costs of filter  37:    25 ( 0.62s )\n",
            "Costs of filter  38:    24 ( 0.63s )\n",
            "Costs of filter  40:    34 ( 0.62s )\n",
            "Costs of filter  41:    32 ( 0.65s )\n",
            "Costs of filter  42:    14 ( 0.66s )\n",
            "Costs of filter  43:    11 ( 0.65s )\n",
            "Costs of filter  44:    21 ( 0.67s )\n",
            "Costs of filter  45:    27 ( 0.68s )\n",
            "Costs of filter  46:    21 ( 0.86s )\n",
            "Costs of filter  47:    26 ( 0.68s )\n",
            "Costs of filter  48:    17 ( 0.69s )\n",
            "Costs of filter  49:    33 ( 0.71s )\n",
            "Costs of filter  50:    46 ( 0.69s )\n",
            "Costs of filter  51:    28 ( 0.70s )\n",
            "Costs of filter  52:    36 ( 0.71s )\n",
            "Costs of filter  53:    18 ( 0.71s )\n",
            "Costs of filter  54:    23 ( 0.71s )\n",
            "Costs of filter  55:    30 ( 0.72s )\n",
            "Costs of filter  56:    24 ( 0.71s )\n",
            "Costs of filter  57:    39 ( 0.73s )\n",
            "Costs of filter  58:    25 ( 0.75s )\n",
            "Costs of filter  59:    68 ( 0.73s )\n",
            "Costs of filter  60:    20 ( 0.74s )\n",
            "Costs of filter  62:    23 ( 0.75s )\n",
            "Costs of filter  63:    21 ( 0.76s )\n",
            "58 filter processed.\n",
            "Compute filters 0 to 128\n",
            "Costs of filter   1:   179 ( 0.99s )\n",
            "Costs of filter   2:   377 ( 1.00s )\n",
            "Costs of filter   3:   428 ( 0.99s )\n",
            "Costs of filter   4:   239 ( 1.02s )\n",
            "Costs of filter   5:   191 ( 1.02s )\n",
            "Costs of filter   6:   615 ( 1.01s )\n",
            "Costs of filter   7:   220 ( 1.03s )\n",
            "Costs of filter   8:   230 ( 1.04s )\n",
            "Costs of filter   9:   184 ( 1.05s )\n",
            "Costs of filter  10:   154 ( 1.07s )\n",
            "Costs of filter  11:   143 ( 1.06s )\n",
            "Costs of filter  12:   454 ( 1.07s )\n",
            "Costs of filter  14:   230 ( 1.08s )\n",
            "Costs of filter  15:   210 ( 1.10s )\n",
            "Costs of filter  16:   181 ( 1.12s )\n",
            "Costs of filter  17:   220 ( 1.13s )\n",
            "Costs of filter  18:   366 ( 1.13s )\n",
            "Costs of filter  19:   234 ( 1.14s )\n",
            "Costs of filter  20:   402 ( 1.17s )\n",
            "Costs of filter  21:   190 ( 1.15s )\n",
            "Costs of filter  22:   271 ( 1.17s )\n",
            "Costs of filter  23:   108 ( 1.15s )\n",
            "Costs of filter  24:   249 ( 1.18s )\n",
            "Costs of filter  25:   359 ( 1.19s )\n",
            "Costs of filter  26:   407 ( 1.20s )\n",
            "Costs of filter  27:   312 ( 1.21s )\n",
            "Costs of filter  28:   292 ( 1.21s )\n",
            "Costs of filter  29:   231 ( 1.22s )\n",
            "Costs of filter  30:   169 ( 1.24s )\n",
            "Costs of filter  32:   485 ( 1.24s )\n",
            "Costs of filter  33:   229 ( 1.26s )\n",
            "Costs of filter  34:   423 ( 1.27s )\n",
            "Costs of filter  35:   120 ( 1.28s )\n",
            "Costs of filter  36:   261 ( 1.29s )\n",
            "Costs of filter  37:   162 ( 1.32s )\n",
            "Costs of filter  38:   359 ( 1.33s )\n",
            "Costs of filter  40:    59 ( 1.29s )\n",
            "Costs of filter  41:   304 ( 1.33s )\n",
            "Costs of filter  42:   273 ( 1.35s )\n",
            "Costs of filter  43:     6 ( 1.38s )\n",
            "Costs of filter  44:   203 ( 1.36s )\n",
            "Costs of filter  45:   420 ( 1.38s )\n",
            "Costs of filter  46:   308 ( 1.40s )\n",
            "Costs of filter  47:   233 ( 1.41s )\n",
            "Costs of filter  48:   207 ( 1.42s )\n",
            "Costs of filter  50:   110 ( 1.45s )\n",
            "Costs of filter  52:   156 ( 1.44s )\n",
            "Costs of filter  53:   101 ( 1.48s )\n",
            "Costs of filter  54:   489 ( 1.48s )\n",
            "Costs of filter  55:   387 ( 1.46s )\n",
            "Costs of filter  56:   489 ( 1.52s )\n",
            "Costs of filter  57:   206 ( 1.51s )\n",
            "Costs of filter  58:   316 ( 1.53s )\n",
            "Costs of filter  59:   359 ( 1.52s )\n",
            "Costs of filter  61:   258 ( 1.59s )\n",
            "Costs of filter  62:   154 ( 1.56s )\n",
            "Costs of filter  63:   145 ( 1.61s )\n",
            "Costs of filter  64:   171 ( 1.62s )\n",
            "Costs of filter  65:   436 ( 1.78s )\n",
            "Costs of filter  66:   261 ( 1.61s )\n",
            "Costs of filter  67:   334 ( 1.65s )\n",
            "Costs of filter  68:   110 ( 1.63s )\n",
            "Costs of filter  70:   348 ( 1.66s )\n",
            "Costs of filter  71:   321 ( 1.68s )\n",
            "Costs of filter  72:   686 ( 1.69s )\n",
            "Costs of filter  73:   308 ( 1.71s )\n",
            "Costs of filter  74:   221 ( 1.72s )\n",
            "Costs of filter  75:   368 ( 1.73s )\n",
            "Costs of filter  76:   364 ( 1.73s )\n",
            "Costs of filter  77:     5 ( 1.76s )\n",
            "Costs of filter  78:   213 ( 1.75s )\n",
            "Costs of filter  79:   185 ( 1.77s )\n",
            "Costs of filter  80:   400 ( 1.82s )\n",
            "Costs of filter  81:   252 ( 1.78s )\n",
            "Costs of filter  82:   217 ( 1.81s )\n",
            "Costs of filter  83:   441 ( 1.83s )\n",
            "Costs of filter  84:   300 ( 1.84s )\n",
            "Costs of filter  85:   426 ( 1.87s )\n",
            "Costs of filter  86:   284 ( 1.85s )\n",
            "Costs of filter  87:   177 ( 1.86s )\n",
            "Costs of filter  88:   317 ( 1.89s )\n",
            "Costs of filter  89:   257 ( 1.88s )\n",
            "Costs of filter  90:   217 ( 1.91s )\n",
            "Costs of filter  91:   433 ( 1.95s )\n",
            "Costs of filter  92:   173 ( 1.93s )\n",
            "Costs of filter  93:   205 ( 1.95s )\n",
            "Costs of filter  94:   228 ( 1.97s )\n",
            "Costs of filter  95:   141 ( 1.97s )\n",
            "Costs of filter  96:   301 ( 2.00s )\n",
            "Costs of filter  97:   564 ( 2.02s )\n",
            "Costs of filter  98:   365 ( 2.02s )\n",
            "Costs of filter  99:   229 ( 2.02s )\n",
            "Costs of filter 100:   215 ( 2.06s )\n",
            "Costs of filter 101:   200 ( 2.08s )\n",
            "Costs of filter 102:   433 ( 2.07s )\n",
            "Costs of filter 103:   283 ( 2.04s )\n",
            "Costs of filter 104:   326 ( 2.09s )\n",
            "Costs of filter 106:   109 ( 2.13s )\n",
            "Costs of filter 107:   561 ( 2.15s )\n",
            "Costs of filter 109:   532 ( 2.17s )\n",
            "Costs of filter 110:   231 ( 2.19s )\n",
            "Costs of filter 111:   385 ( 2.18s )\n",
            "Costs of filter 112:   247 ( 2.22s )\n",
            "Costs of filter 113:   286 ( 2.18s )\n",
            "Costs of filter 114:   368 ( 2.22s )\n",
            "Costs of filter 115:   191 ( 2.24s )\n",
            "Costs of filter 116:   295 ( 2.29s )\n",
            "Costs of filter 117:   441 ( 2.27s )\n",
            "Costs of filter 118:   143 ( 2.27s )\n",
            "Costs of filter 119:    67 ( 2.29s )\n",
            "Costs of filter 120:   335 ( 2.31s )\n",
            "Costs of filter 121:   242 ( 2.34s )\n",
            "Costs of filter 122:   321 ( 2.34s )\n",
            "Costs of filter 124:   160 ( 2.36s )\n",
            "Costs of filter 125:   488 ( 2.41s )\n",
            "Costs of filter 126:   160 ( 2.44s )\n",
            "Costs of filter 127:   348 ( 2.43s )\n",
            "117 filter processed.\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hfQatJaFfIoG",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}
